package com.qf.fmall2302.index.service.impl;

import cn.hutool.core.collection.CollStreamUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.qf.fmall2302.index.entity.Category;
import com.qf.fmall2302.index.mapper.CategoryMapper;
import com.qf.fmall2302.index.service.ICategoryService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.qf.fmall2302.product.entity.Product;
import com.qf.fmall2302.product.mapper.ProductMapper;
import com.qf.fmall2302.product.service.IProductService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.*;
import java.util.concurrent.TimeUnit;
import java.util.function.Function;
import java.util.stream.Collectors;

/**
 * <p>
 * 商品分类 服务实现类
 * </p>
 *
 * @author dongjl
 * @since 2023-08-23
 */
@Service
public class CategoryServiceImpl extends ServiceImpl<CategoryMapper, Category> implements ICategoryService {

    @Autowired
    IProductService productService;

    @Autowired
    RedisTemplate redisTemplate;

//    @Transactional
    @Override
    public List<Category> categoryList() throws Exception {

        // 从缓存中查询是否有分类数据的结果，如果有直接返回
        String key = "fmall:categoryList";
        List<Category> cacheResult = (List<Category>) redisTemplate.opsForValue().get(key);
        if (cacheResult!=null){
            // 缓存命中
            return cacheResult;
        }

        // 解决缓存击穿问题
        // 申请一把分布式锁，如果申请锁成功的线程，继续去访问数据库查询数据。 setnx
        // 申请锁失败的线程，不要访问数据库了，自旋(循环结构中等一会去检查一次缓存，有就退出自旋)
        String lockkey = "fmall:categoryList:lock";
        Boolean flag = redisTemplate.opsForValue().setIfAbsent(lockkey, new Date());

        if (flag){  // 申请分布式锁成功
            List<Category> result;
            try {
                // 可以通过baseMapper直接拿到 CategoryMapper
                CategoryMapper categoryMapper = this.getBaseMapper();
                List<Category> categories = categoryMapper.selectList(null);

                result = buildCategoryTree(categories);
                // 把结果写入 redis缓存中
                redisTemplate.opsForValue().set(key,result,300, TimeUnit.SECONDS);
            } finally {
                redisTemplate.delete(lockkey);  // 释放分布式锁
            }

            return result;
        }else {
            // 申请分布式锁失败的线程如何处理？
            // 自旋等待redis中的数据被拿到分布式锁的线程写入
            for (int i = 0; i < 10; i++) {
                Thread.sleep(200);
                List<Category> result = (List<Category>) redisTemplate.opsForValue().get(key);
                if (result!=null){
                    return result;
                }
            }

            // 如果10次自旋之内仍然没有拿到数据，那么抛出异常
            throw new Exception("服务器目前有问题，请稍后再试");

        }


    }

    @Override
    public List<Category> categoryList2() {

        //定义返回的数组
//        List<Category> categiryLevel1 = new ArrayList<>();
        //全查出来
        List<Category> list = this.list();
        //组成一级菜单
//        for (Category category : list) {
//            if (category.getCategoryLevel() == 1)
//                categiryLevel1.add(category);
//        }

        // 把 List<Category> ----> Map<category_levle,List<在该level下的所有的分类信息对象>>
        Map<Integer, List<Category>> levelCategoryMap
                = list.stream().collect(Collectors.groupingBy(Category::getCategoryLevel));


        List<Category> level1CategoryList = levelCategoryMap.get(1);


        // 把 List<Category> --> Map<parentId,List<在该parentid下的所有的分类信息对象>>
        Map<Integer, List<Category>> categoryMap = list.stream()
                .collect(Collectors.groupingBy(Category::getParentId));

        // 给一级分类挂二级分类
        for (int i = 0; i < level1CategoryList.size(); i++) {
            Category category = level1CategoryList.get(i);
            List<Category> categories2 = categoryMap.get(category.getCategoryId());
            category.setCategories(categories2);
        }

        // 给二级分类挂三级分类
        List<Category> level2Categories = levelCategoryMap.get(2);
        for (Category level2Category : level2Categories) {
            List<Category> level3Categories = categoryMap.get(level2Category.getCategoryId());
            level2Category.setCategories(level3Categories);
        }

        return level1CategoryList;
    }

    @Override
    public List<Category> categoryRecommends() {
        int count = 0;
        //1. 查询一级分类信息
        count++;
        List<Category> categoryList = this.list(new QueryWrapper<Category>().eq("category_level", 1));
        //2. 给一级分类填充商品信息 （商品销量前六）
        for (Category category : categoryList) {
            count++;
            // 查询当前分类下销量前六商品
            List<Product> products = productService.list(new QueryWrapper<Product>()
                    .eq("root_category_id", category.getCategoryId())
                    .orderByDesc("sold_num")
                    .last("limit 6")
            );

            if (products==null || products.size()==0){
                category.setProducts(new ArrayList<>());
            }else {
                count++;
                // 为商品添加图片信息
                productService.addPic(products);
            }
            category.setProducts(products);

        }

        System.out.println(count);
        return categoryList;
    }

    @Override
    public List<Category> categoryRecommendsBysql() {
        return null;
    }

    private List<Category> buildCategoryTree(List<Category> categories) {
        List<Category> categoryTree = new ArrayList<>();

        //创建map集合，用来存放数据库中所有数据
        Map<Integer, Category> categoryMap = new HashMap<>();

        //向map集合添加数据
        for (Category category : categories) {
            categoryMap.put(category.getCategoryId(), category);
        }

        // 如何使用stream流的方式，实现 List<Category> ---> Map<分类id，分类对象> 转换
//        Map<Integer, Category> categoryMap1 = categories.stream().collect(Collectors.toMap(Category::getCategoryId, category -> category));

        //判断层级关系
        for (Category category : categories) {
            //判断每一个对象的父id是否为0，成立添加到集合中
            if (category.getParentId() == 0) {
                categoryTree.add(category);
            } else {
                //通过当前对象的父id号,从map集合获取对象
                Category parentCategory = categoryMap.get(category.getParentId());
                if (parentCategory != null) {
                    if (parentCategory.getCategories() == null) {
                        parentCategory.setCategories(new ArrayList<>());

                    }
                    parentCategory.getCategories().add(category);
                }
            }
        }
        return categoryTree;
    }
}
